/* 
 * Copyright 2011 kOSMik.
 * This file is part of kOSMik.
 * 
 * kOSMik is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * kOSMik is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with kOSMik.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * kOSMik:
 * Open Street Map - Editor.
 * http://code.google.com/p/swp-dv-ws2010-osm-2/
 */

package de.fuberlin.kosmik.export;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import android.os.Bundle;
import de.fuberlin.kosmik.data.dao.Poi;
import de.fuberlin.kosmik.data.dao.Way;

/**
 * Create OSM complaint XML-Strings from DAO Model and write them into the
 * xmlWriter.
 * 
 * @author Simon
 * 
 */
public class OsmWriter {

	/**
	 * XML KEYS: META.
	 */
	private static final String ROOT = "osm";
	private static final String HEADER = "blargh";

	/**
	 * XML KEYS: COMMON.
	 */
	private static final String USER = "user";
	private static final String UID = "uid";
	private static final String TIMESTAMP = "timestamp";
	private static final String VISIBLE = "visible";
	private static final String VERSION = "version";
	private static final String CHANGESET = "changeset";
	private static final String ID = "id";

	/**
	 * XML KEYS: TAG.
	 */
	private static final String TAG = "tag";
	private static final String KEY = "k";
	private static final String VALUE = "v";

	/**
	 * XML KEYS: NODE.
	 */
	private static final String LATITUDE = "lat";
	private static final String LONGITUDE = "lon";
	private static final String NODE = "nd";

	/**
	 * XML KEYS: WAY / AREA.
	 */
	private static final String WAY = "way";
	private static final String REFERNCE = "ref";

	private final XmlWriter xmlWriter;

	private static HashMap<String, String> metaAttributes = new HashMap<String, String>(4); // common

	// values
	// like

	// UID, changeset...

	/**
	 * Implicitly writes declaration and header.
	 * 
	 * @param xmlWriter fully initialized xmlwriter.
	 */
	public OsmWriter(XmlWriter xmlWriter) {
		this.xmlWriter = xmlWriter;
		xmlWriter.declaration();
		xmlWriter.content(HEADER);
	}

	/**
	 * Set the meta attributes of each OSM-Element.
	 * 
	 * @param user name of the user.
	 * @param uid uid of the user.
	 * @param visible whether the object is deleted or not in the database.
	 * @param changeset The changeset in which the objects are created or
	 *            updated.
	 */
	public void setMetaAttibutes(String user, int uid, boolean visible, int changeset) {
		metaAttributes.put(USER, user);
		metaAttributes.put(UID, Integer.toString(uid));
		metaAttributes.put(VISIBLE, visible ? "true" : "false");
		metaAttributes.put(CHANGESET, Integer.toString(changeset));
	}

	/**
	 * Write a node.
	 * 
	 * @param point to be writen.
	 */
	/*
	 * <node id="25496583" lat="51.5173639" lon="-0.140043" version="1"
	 * changeset="203496" user="80n" uid="1238" visible="true"
	 * timestamp="2007-01-28T11:40:26Z"> <tag k="highway" v="traffic_signals"/>
	 */
	public void writeNode(Poi point) {
		Map<String, String> attributes = getAttributesFromPoi(point); // lon,lat,etc.

		xmlWriter.elementWithAttributes(NODE, attributes);

		writeTags(point.values); // tags

		xmlWriter.endElement(NODE);

	}

	/**
	 * Write a way or area.
	 * 
	 * @param way way to be written.
	 * @param nodes the nodes that are in this way.
	 */
	/*
	 * <way id="5090250" visible="true" timestamp="2009-01-19T19:07:25Z"
	 * version="8" changeset="816806" user="Blumpsy" uid="64226"> <nd
	 * ref="822403"/> <nd ref="21533912"/> <tag k="highway" v="unclassified"/>
	 * <tag k="name" v="Clipstone Street"/> <tag k="oneway" v="yes"/> </way>
	 */
	public void writeWay(Way way, Collection<Poi> nodes) {

		Map<String, String> attributes = getAttributesFromWay(way);

		xmlWriter.elementWithAttributes(WAY, attributes);

		for (Poi node : nodes) {
			Map<String, String> refKv = new HashMap<String, String>(1);
			refKv.put(REFERNCE, Long.toString(node.osmId));
			xmlWriter.emptyElementWithAttributes(NODE, refKv);
		}

		writeTags(way.tags); // tags
		xmlWriter.endElement(WAY);
	}

	/**
	 * Close the root entry.
	 */
	public void closeRoot() {
		xmlWriter.endElement(ROOT);
		xmlWriter.finish();
	}

	/**
	 * Write tags.For each Entry: <tag k="name" v="Clipstone Street"/> will be
	 * written.
	 * 
	 * @param tags to be written.
	 */
	private void writeTags(Bundle tags) {

		for (String key : tags.keySet()) {
			Map<String, String> kvMap = new HashMap<String, String>(2);

			kvMap.put(KEY, key);
			kvMap.put(VALUE, kvMap.get(key));

			xmlWriter.emptyElementWithAttributes(TAG, kvMap);
		}
	}

	/**
	 * Create map that stores id,lat,long,etc. from a POI.
	 * 
	 * @param point the point.
	 * @return OSM-Complaint kv-map for nodes.
	 */
	/*
	 * <node id="25496583" lat="51.5173639" lon="-0.140043" version="1"
	 * changeset="203496" user="80n" uid="1238" visible="true"
	 * timestamp="2007-01-28T11:40:26Z">
	 */
	private Map<String, String> getAttributesFromPoi(Poi point) {
		Map<String, String> attributes = new HashMap<String, String>(5);
		/* poi/node specific stuff */
		attributes.put(ID, Long.toString(point.osmId));
		attributes.put(LATITUDE, Double.toString(point.lat));
		attributes.put(LONGITUDE, Double.toString(point.lng));
		attributes.put(TIMESTAMP, TypeConverter.convertTime(point.timestamp));
		attributes.put(VERSION, Integer.toString(point.version));
		/* stuff that is common to all osm-objects */
		attributes.putAll(metaAttributes);

		return attributes;
	}

	/**
	 * Create map that stores id,etc. from a way.
	 * 
	 * @param way the way.
	 * @return OSM-Complaint kv-map for ways.
	 */
	/*
	 * <way id="5090250" visible="true" timestamp="2009-01-19T19:07:25Z"
	 * version="8" changeset="816806" user="Blumpsy" uid="64226"> <nd
	 * ref="822403"/> <nd ref="21533912"/> <tag k="highway" v="unclassified"/>
	 * <tag k="name" v="Clipstone Street"/> <tag k="oneway" v="yes"/> </way>
	 */
	private Map<String, String> getAttributesFromWay(Way way) {
		Map<String, String> attributes = new HashMap<String, String>(2);
		/* way specific stuff */
		attributes.put(ID, Long.toString(way.osmId));
		attributes.put(TIMESTAMP, TypeConverter.convertTime(way.timestamp));
		attributes.put(VERSION, Integer.toString(way.version));
		/* stuff that is common to all osm-objects */
		attributes.putAll(metaAttributes);

		return attributes;
	}

}
